import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { Repository } from 'typeorm';
import { LoginRegister } from './entities/login-register.entity';
import { Logger } from 'src/common/logger/logger';
import { InjectRepository } from '@nestjs/typeorm';
import { JwtService } from '@nestjs/jwt';
import crypto from 'crypto';
import { RedisService } from 'src/common/redis/redis.service';
import * as svgCaptcha from 'svg-captcha';

function md5(str) {
  const hash = crypto.createHash('md5');
  hash.update(str);
  return hash.digest('hex');
}

@Injectable()
export class LoginRegisterService {
  constructor(
    @Inject(Logger)
    private readonly logger: Logger,

    @InjectRepository(LoginRegister)
    private readonly userRepository: Repository<LoginRegister>,

    private readonly jwtService: JwtService,

    @Inject(RedisService)
    private readonly redisService: RedisService,
  ) {}

  /**
   * 注册用户
   * @param user
   * @returns
   */
  async register(user: RegisterDto) {
    this.logger.log('register user', JSON.stringify(user));
    const found_user = await this.userRepository.findOne({
      where: {
        username: user.username,
      },
    });

    if (found_user) {
      throw new HttpException('用户已存在', HttpStatus.OK);
    }

    const new_user = new LoginRegister();
    new_user.username = user.username;
    new_user.password = md5(user.password);

    try {
      await this.userRepository.save(new_user);
      return '注册成功';
    } catch (error) {
      this.logger.error('register error', error);
      throw new HttpException('注册失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * 登录用户
   * @param user
   * @returns
   */
  async login(user: LoginDto) {
    // 验证验证码
    const captchaValid = await this.validateCaptcha(
      user.captchaId,
      user.captcha,
    );
    if (!captchaValid) {
      throw new HttpException('验证码错误或已过期', HttpStatus.OK);
    }

    const found_user = await this.userRepository.findOne({
      where: {
        username: user.username,
      },
    });

    if (!found_user) {
      throw new HttpException('用户名不存在', HttpStatus.OK);
    } else {
      if (md5(user.password) !== found_user.password) {
        throw new HttpException('密码错误', HttpStatus.OK);
      }

      // 这里可以根据实际情况从数据库或其他地方获取用户角色
      // 为了演示，这里简单地根据用户名设置角色
      const roles =
        found_user.username === 'admin' ? ['admin', 'user'] : ['user'];

      // 生成JWT token，包含用户角色信息
      const token = this.jwtService.sign({
        username: found_user.username,
        userId: found_user.id,
        roles: roles, // 包含角色信息
      });

      return {
        retcode: HttpStatus.OK,
        data: {
          message: '登录成功',
          token,
          user: {
            username: found_user.username,
            id: found_user.id,
            roles: roles,
            password: found_user.password,
          },
        },
      };
    }
  }

  /**
   * 生成验证码
   * expire 验证码过期时间，单位秒，默认5分钟
   * @returns 验证码图片URL
   */
  async generateCaptcha(expire: number) {
    // 生成优化后的验证码
    const captcha = svgCaptcha.create({
      size: 4, // 验证码字符数量，4个字符更容易识别
      ignoreChars: '0oO1iIlLnN', // 忽略容易混淆的字符
      noise: 2, // 添加适量干扰线增加安全性
      background: '#000', // 使用黑色背景，减少视觉疲劳
      height: 50, // 增加高度提高可读性
      width: 140, // 增加宽度给字符更多空间
      fontSize: 36, // 调整字体大小
      color: true, // 启用彩色文字
    });

    // 定义一组鲜艳的颜色，在黑色背景上清晰可见
    const colors = [
      '#ff3366', // 粉红色
      '#33ccff', // 蓝色
      '#ffcc00', // 黄色
      '#66ff99', // 绿色
      '#ff9900', // 橙色
      '#cc66ff', // 紫色
    ];
    let colorIndex = 0;

    captcha.data = captcha.data
      // 优化文本颜色，使每个数字显示不同的彩色
      .replace(/fill="#(?!(?:000))([A-Fa-f0-9]{6})"/g, (match) => {
        // 保留非文本元素的颜色（如干扰线）
        if (match.includes('path') || match.includes('circle')) {
          return match;
        }
        // 为每个数字分配不同的颜色，循环使用颜色数组
        const color = colors[colorIndex % colors.length];
        colorIndex++;
        return `fill="${color}"`;
      })
      // 增加文字粗细
      .replace(/<text/g, '<text font-weight="bold"')
      // 增加干扰线的可见性但不过度干扰
      .replace(
        /stroke="#[A-Fa-f0-9]{6}"/g,
        'stroke="#666666" stroke-width="1"',
      );

    // 生成随机ID用于标识验证码
    const captchaId = crypto.randomUUID();
    const captchaKey = `captcha:${captchaId}`;

    // 将验证码存储到Redis，设置5分钟过期
    await this.redisService.set(
      captchaKey,
      captcha.text.toLowerCase(),
      expire || 300,
    );

    // 将SVG转换为base64编码的URL
    const svgData = captcha.data;
    const base64Data = Buffer.from(svgData).toString('base64');
    const imageUrl = `data:image/svg+xml;base64,${base64Data}`;

    return {
      captchaId,
      imageUrl,
    };
  }

  /**
   * 验证验证码
   * @param captchaId 验证码ID
   * @param userInput 用户输入的验证码
   * @returns 是否验证成功
   */
  async validateCaptcha(
    captchaId: string,
    userInput: string,
  ): Promise<boolean> {
    const captchaKey = `captcha:${captchaId}`;
    const storedCaptcha = await this.redisService.get(captchaKey);

    if (!storedCaptcha) {
      return false;
    }

    // 验证成功后删除验证码，防止重复使用
    await this.redisService.del(captchaKey);

    return storedCaptcha.toLowerCase() === userInput.toLowerCase();
  }
}
